package com.learn.core.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author PC
 * aop工具类
 */
@Component
public class AopUtils {

    /**
     * 通过el表达式获取值
     *
     * @param joinPoint 切点
     * @param elStr     el表达式
     * @return el表达式获取的值, 默认返回String类型
     */
    public String getElValue(ProceedingJoinPoint joinPoint, String elStr) {
        return this.getElValue(joinPoint, elStr, String.class);
    }

    /**
     * 通过el表达式获取值
     *
     * @param joinPoint 切点
     * @param elStr     el表达式
     * @param tClass    待转换的类
     * @return el表达式获取的值
     */
    public <T> T getElValue(ProceedingJoinPoint joinPoint, String elStr, Class<T> tClass) {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        // 创建表达式解析器
        ExpressionParser parser = new SpelExpressionParser();
        // 创建评估上下文
        EvaluationContext context = new StandardEvaluationContext();

        // 将方法参数绑定到上下文中
        String[] paramNames = signature.getParameterNames();
        Object[] paramValues = joinPoint.getArgs();
        if (paramValues.length == 0) {
            return null;
        }
        for (int i = 0; i < paramNames.length; i++) {
            context.setVariable(paramNames[i], paramValues[i]);
        }

        // 解析el表达式的值
        return parser.parseExpression(elStr).getValue(context, tClass);
    }

    /**
     * 获取方法的入参Map
     * @param joinPoint 切点
     * @return 方法入参map
     */
    public Map<String, Object> getInputParams(ProceedingJoinPoint joinPoint) {

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        // 将方法参数绑定到上下文中
        String[] paramNames = signature.getParameterNames();
        Object[] paramValues = joinPoint.getArgs();
        if (paramValues.length == 0) {
            return new HashMap<>(16);
        }
        Map<String, Object> resultMap = new HashMap<>(paramValues.length);
        for (int i = 0; i < paramNames.length; i++) {
            resultMap.put(paramNames[i], paramValues[i]);
        }
        return resultMap;
    }
}
